package yicr.untils;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class NslUtilFilePath {

    /**
     * 根据 相对classpath目录 获得绝对路径
     * @param relativePath 相对classpath目录,目录形式如:"config/database.prop",注意首字符不能出现"/"
     * @return
     */
    public static String getAbsPathBaseOnClassPath(String relativePath) throws URISyntaxException {
        if(relativePath==null){
            throw new RuntimeException("RelativePath is null");
        }
        URL url=NslUtilFilePath.class.getClassLoader().getResource(relativePath);
        if(url==null){
            throw new RuntimeException("Url is null");
        }
        URI uri = new URI(url.toString());
        String result=uri.getPath();

        if(result!=null){
            result=result.substring(1, result.length());
        }else{
            result="";
        }
        return result;

    }

    /** 获取指定目录下的 直接 儿子文件，不包含目录
     * @param dir abs path 0f directory
     * @return  file list
     */
    public static List<File> getSonFilesExcludeDirOfDir(File dir){
        List<File> files=new ArrayList<>();
        if(dir.isDirectory()){
            File[] items=dir.listFiles();
            for (File item : items) {
                if(item.isDirectory()){
                    continue;
                }
                files.add(item);
            }
        }
        return  files;
    }

    /**
     * 获取直接子目录下的，目录组成的List
     * @param file
     * @return
     */
    public static List<File> getSonDirsExcludeFileOfDir(File file){
        if(!file.exists() || ! file.isDirectory()){
            return null;
        }
        List<File> fileList=new ArrayList<>();
        return fileList;

    }

    // 获取磁盘根目录list
    public static List<File> 	getDiskRootFileList(){
        File[] roots = File.listRoots();
//        for (int i = 0; i < roots.length; i++) {
//            System.out.print(roots[i].getPath()+"; ");//磁盘路径
//            System.out.print(roots[i].getTotalSpace()/1024/1024/1024+"; ");//磁盘总空间大小
//            System.out.print(roots[i].getUsableSpace()/1024/1024/1024+"; ");//剩余磁盘空间大小
//            System.out.println(roots[i].getFreeSpace()/1024/1024/1024);//剩余磁盘空间大小
//        }
//
        return Arrays.asList(roots);
    }


//    /**
//     * 获取 直接儿子、目录组成 的file List
//     * @param dir
//     * @return
//     */
//    public static List<File> getSonDirFileListOfDir(File dir) throws FileNotFoundException {
//        NslUtilFilePath.assertDirExistNotFile(dir);
//        return Arrays.stream(dir.listFiles()).toList();
//    }

    /**
     * 递归获取 指定目录下，所有文件和目录 的集合
     * @param dir
     * @return
     * @throws FileNotFoundException
     */
    public static List<File> getFileDirListOfDirWithRecursion(File dir) throws FileNotFoundException {
        NslUtilFilePath.assertDirExistNotFile(dir);
        List<File> fileList=new ArrayList<>();
        File[] files=dir.listFiles();
        Arrays.stream(files).forEach(e->{
            fileList.add(e);
            if(e.isDirectory()){
                try {
                    fileList.addAll(getFileDirListOfDirWithRecursion(e));
                } catch (FileNotFoundException ex) {
                    throw new RuntimeException(e.getAbsolutePath()+" is not valid dir path");
                }
            }
        });
        return fileList;
    }

    /**
     * 递归获取 指定目录下，所有文件和目录 的集合,考虑递归深度
     * 当前目录为 depth=1
     * @param dir
     * @return
     * @throws FileNotFoundException
     */
    public static List<File> getFileDirListOfDirWithRecursionAccordingDepth(File dir,int depth) throws FileNotFoundException {
        NslUtilFilePath.assertDirExistNotFile(dir);
        List<File> fileList=new ArrayList<>();
        File[] files=dir.listFiles();
        Arrays.stream(files).forEach(e->{
            fileList.add(e);
            final int currentDepth=depth-1;
            if(e.isDirectory() && currentDepth>0){
                try {
                    fileList.addAll(getFileDirListOfDirWithRecursionAccordingDepth(e,currentDepth));
                } catch (FileNotFoundException ex) {
                    throw new RuntimeException(e.getAbsolutePath()+" is not valid dir path");
                }
            }
        });
        return fileList;
    }


    /**
     * 递归获取 指定目录下，所有文件 的List，不包含 dir
     * @param dir
     * @return
     * @throws FileNotFoundException
     */
    public static List<File> getFileListExcludeDirOfDirWithRecursion(File dir) throws FileNotFoundException {
        List<File> allFileList=getFileDirListOfDirWithRecursion(dir);
        return allFileList.stream().filter(f->f.isFile()).collect(Collectors.toList());
    }



    /**
     * 递归获取 指定目录下，所有目录 组成的List，不包含 file
     * @param dir
     * @return
     * @throws FileNotFoundException
     */
    public static List<File> getDirListExcludeFileOfDirWithRecursion(File dir) throws FileNotFoundException {
        List<File> allFileList=getFileDirListOfDirWithRecursion(dir);
        return allFileList.stream().filter(f->f.isDirectory()).collect(Collectors.toList());
    }



//    /**
//     * 获取指定目录下， 直接 儿子 文件或目录，组成的List, 并包含指定的关键词
//     * @param dir
//     * @param keywordList
//     * @return
//     */
//    public static List<File> getSonFileListByKeywordList(File dir,List<String> keywordList) throws FileNotFoundException {
//        NslUtilFilePath.assertDirExistNotFile(dir);
//        List<File> fileList=getSonDirFileListOfDir(dir);
//        List<File> filterdFileList=fileList.stream().filter(f->{
//            String fileName=getFileName(f);
//            boolean isMatch=keywordList.stream().anyMatch(keyword->keyword.equalsIgnoreCase(fileName));
//            return isMatch;
//        }).collect(Collectors.toList());
//        return filterdFileList;
//    }




    /**
     * 断言路径存在，并且为文件，不存在抛异常
     * @param filePath
     */
    static public void assertFileExistNotDir(String filePath) throws FileNotFoundException {
        assertFileExistNotDir(new File(filePath));
    }

    /**
     * 断言路径存在，并且为文件，不存在抛异常
     * @param file
     */
    static public void assertFileExistNotDir(File file) throws FileNotFoundException {
        boolean flag=file.exists();
        if(!flag){
            throw new FileNotFoundException("传入file("+file.getAbsolutePath()+")"+"不存在");
        }
        boolean isFile=file.isFile();
        if(!isFile){
            throw new FileNotFoundException("传入file("+file.getAbsolutePath()+")"+"不为文件");
        }
    }

    /**
     * 断言 dir 存在，并为目录，非文件
     * @param dir
     */
    static public void assertDirExistNotFile(File dir) throws FileNotFoundException {
        boolean flag=dir.exists();
        if(!flag){
            throw new FileNotFoundException("传入file("+dir.getAbsolutePath()+")"+"不存在");
        }
        boolean directory=dir.isDirectory();
        if(!directory){
            throw new FileNotFoundException("传入file("+dir.getAbsolutePath()+")"+"不为目录");
        }
    }

    /**
     * 断言 dirPath 存在，并为目录，非文件
     * @param dirPath
     * @throws FileNotFoundException
     */
    static public void assertDirExistNotFile(String dirPath) throws FileNotFoundException {
        assertDirExistNotFile(new File(dirPath));
    }

    /**
     * 获得工程根目录，如 D:\my_hello_project
     * @return
     */
    static public   String getProjectAbsPath(){
        return System.getProperty("user.dir");
    }


    /**
     * 根据文件路径，加入uuid标识
     * 如: d:\abc\demo1.xlsx =>  d:\abc\demo1_uuid.xlsx
     * @param filePath
     * @param idToken
     * @return
     */
    static public String buildFilePathWithIdTokenAtRear(String filePath, String idToken){

        if(filePath.endsWith("/") || filePath.endsWith(File.separator)){
            throw  new RuntimeException("传入的filePath 不合法");
        }
        String filePathWithoutExtension=getFilePathWithoutExtension(filePath);
        String filePathExtension=getFileExtension(filePath);
        return filePathWithoutExtension+"_"+idToken+"."+filePathExtension;
    }

    /**
     * 根据文件路径，加入uuid标识
     * 如: d:\abc\demo1.xlsx =>  d:\abc\demo1_uuid.xlsx
     * @param filePath
     * @return
     */
    static public String buildFilePathWithUuidAtRear(String filePath){
        String uuid= NslUtilUuid.generateUuidWithOutHyphen();
        return buildFilePathWithIdTokenAtRear(filePath,uuid);
    }

    /**
     * 根据文件路径，加入 System time 标识
     * 如: d:\abc\demo1.xlsx =>  d:\abc\demo1_11234354.xlsx
     * @param filePath
     * @return
     */
    static public String buildFilePathWithSystemTimestampAtRear(String filePath){

        return buildFilePathWithIdTokenAtRear(filePath,System.currentTimeMillis()+"");
    }

    static public String getClassPath(){
        // classPath ：/D:/Java_Projects/ideaIU-2022.2.3.win_projects/my-youlai/target/test-classes/
        String classPath=ClassLoader.getSystemResource(".").getPath();
        classPath=classPath.substring(1);
        if(File.separator.equalsIgnoreCase("\\")){
            // classPath D:\\Java_Projects\\ideaIU-2022.2.3.win_projects\\my-youlai\\target\\test-classes\\
            // /在字符串中是转义符
            classPath=classPath.replaceAll("/","\\\\");
        }else{
            classPath=classPath.replaceAll("/",File.separator);
        }
        return classPath;
    }

    /**
     * 获取指定的class 源代码文件的绝对路径，
     * 环境： maven maven结构目录：
     * 生成class的目录： project_path/target/classes
     * src文件的目录： project_path/src/main/java/
     * @param clazz
     * @return
     * @throws URISyntaxException
     */
    public static String getSpecifiedClassAbsPath(Class clazz) {
        URL url=clazz.getResource("");
        URI uri= null;
        try {
            uri = url.toURI();
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
        // /D:/Java_Projects/ideaIU-2022.2.3.win_projects/gaoxin_transmission/target/test-classes/com/nsl/ams/utils/
        String packPath=uri.getPath();

        String srcTargetKey="target/classes";
        String testSrcTargetKey="target/test-classes";

        String srcSourcePath="src/main/java";
        String testSrcSourcePath="src/test/java";

        String sourcePackPath;

        if(packPath.contains(srcTargetKey)){
            sourcePackPath=packPath.replace(srcTargetKey,srcSourcePath);
        }else if(packPath.contains(testSrcTargetKey)){
            sourcePackPath=packPath.replace(testSrcTargetKey,testSrcSourcePath);
        }else{
            throw new RuntimeException(" 运行环境不在maven 结构目录中");
        }
        String codeUriString=sourcePackPath+clazz.getSimpleName()+".java";
        File srcFile=new File(codeUriString.substring(1));
        if(!srcFile.exists()){
            throw new RuntimeException("传入的Class("+clazz+") 源文件不存在，请检查运行环境");
        }
        return srcFile.getAbsolutePath();
    }

    /**
     * 根据文件路径返回文件名称，不考虑文件是否存在
     * 可以根据以下几种，
     * f:\\aFolder\\1.xls
     * bFolder\\1.xls
     * 1.xls
     * 1
     * 都返回一致结果为：1.xls,最后一个返回1,
     * @param filePath
     * @return
     */
    static public String getFileName(String filePath){
       return NslUtilString.getLastFragment(filePath,"\\");
    }

    static public String getFileName(File file){
        String filePath=file.getAbsolutePath();
        return getFileName(filePath);

    }

    /**
     * 根据 路径Lit 获取 文件名List,包含文件类型后缀
     * @param filePathStringList
     * @return
     */
    static public List<String> getFileNameOfPathStringList(List<String> filePathStringList){
       return filePathStringList.stream().map(path->getFileName(path)).collect(Collectors.toList());
    }

    /**
     *
     * 根据 路径Lit 获取 文件名List,包含文件类型后缀
     * @param fileList
     * @return
     */
    static public List<String> getFileNameOfFileList(List<File> fileList){
        return fileList.stream().map(path->getFileName(path)).collect(Collectors.toList());
    }


    /**
     * 根据文件路径返回文件名称,文件名不包含扩展名
     * 可以根据以下几种，
     * f:\\aFolder\\1.xls
     * bFolder\\1.xls
     * 1.xls
     * 1
     * 都返回一致结果为：1
     * @param filePath
     * @return
     */
    static public String getFileNameWithoutExtension(String filePath){
        String fileName= NslUtilString.getLastFragment(filePath,"\\");
        int index=fileName.lastIndexOf(".");
        if(index==-1){
            return fileName;
        }else{
            return fileName.substring(0,index);
        }
    }

    /**
     * 根据文件路径返回文件路径名称,文件路径名不包含扩展名
     * 可以根据以下几种，
     * f:\\aFolder\\1.xls
     * 返回结果为：f:\\aFolder\\1
     * @param filePath
     * @return
     */
    static public String getFilePathWithoutExtension(String filePath){
        if(filePath.endsWith("/") || filePath.endsWith(File.separator)){
            throw  new RuntimeException("传入的filePath 不合法，可能为文件夹");
        }
        if(filePath.lastIndexOf(".")==-1){
            throw  new RuntimeException("传入的filePath 不包含扩展名");
        }
        return filePath.substring(0,filePath.lastIndexOf("."));
    }

    /**
     * 根据相对classpath的路径返回，绝对路径
     * 可以根据以下几种，
     * abc\def
     * abc\def\
     * abc/def
     * /abc/def/
     * 都返回一致结果为：D:\Java_Projects\ideaIU-2022.2.3.win_projects\my-youlai\target\classes\abc\def
     * @param relativePath
     * @return
     */
    static public String getFilePathBasedOnClassPath(String relativePath){
        // /abc=>abc
        if(relativePath.startsWith("/")){
            relativePath=relativePath.substring(1);
        }

        // \\abc=>abc
        if(relativePath.startsWith("\\\\")){
            relativePath=relativePath.substring(2);
        }

        // abc/efg => abc\\efg
        if(File.separator.equalsIgnoreCase("\\")){
            relativePath=relativePath.replaceAll("/","\\\\");
        }

        if(relativePath.endsWith("\\")){
            relativePath=relativePath.substring(0,relativePath.length()-1);
        }

        if(File.separator.equalsIgnoreCase("\\")){
            return getClassPath()+relativePath;
        }else{
            return getClassPath()+File.separator+relativePath;
        }
    }

    /**
     * 返回 文件的扩展名，如 d:\abc\1.xlsx，返回 xlsx
     * 有个缺陷，如果 传入的为目录 d:\ab.c 的话，返回的是c
     * @param filePath
     * @return
     */
    static public String getFileExtension(String filePath){
        if(filePath.endsWith("/") || filePath.endsWith(File.separator)){
            throw  new RuntimeException("传入的filePath 不合法，可能为文件夹");
        }
        if(filePath.lastIndexOf(".")==-1){
            throw  new RuntimeException("传入的filePath 不包含扩展名");
        }

        return filePath.substring(filePath.lastIndexOf(".")+1,filePath.length());
    }

    /**
     * 将 d:\abc\1.xlsx 根据传入的 {"x1","y2"} 生成文件路径为 d:\abc\1_x1_y2.xlsx
     * @param filePath filePath是文件路径，且有以.分割结束的扩展名
     * @param suffixes {"x1","y2"}
     * @param fileSeparator 分隔符，如 "_"
     * @return
     */
    static public String buildFilePathWithSuffixes(String filePath,String[] suffixes,String fileSeparator){
        if(filePath.endsWith("/") || filePath.endsWith(File.separator)){
            throw  new RuntimeException("传入的filePath 不合法，可能为文件夹");
        }
        if(filePath.lastIndexOf(".")==-1){
            throw  new RuntimeException("传入的filePath 不包含扩展名");
        }
        String filePathWithoutExtension=getFilePathWithoutExtension(filePath);
        String fileExtension=getFileExtension(filePath);
        for (String suffix : suffixes) {
            filePathWithoutExtension+=fileSeparator+suffix;
        }
//        filePathWithoutExtension=filePathWithoutExtension.substring(0,filePathWithoutExtension.length()-1);
        return filePathWithoutExtension+"."+fileExtension;
    }

    /**
     * 将 d:\abc\1.xlsx 根据传入的 {"x1","y2"} 生成文件路径为 d:\abc\1_x1_y2.xlsx
     * @param filePath filePath是文件路径，且有以.分割结束的扩展名
     * @param suffixes {"x1","y2"}
     * @return
     */
    static public String buildFilePathWithSuffixes(String filePath,String[] suffixes){
        return buildFilePathWithSuffixes(filePath,suffixes,"_");
    }


    public static void main(String[] args) {
        System.out.println(getClassPath());

        String relativePath="abc\\def";
        System.out.println(getFilePathBasedOnClassPath(relativePath));
        relativePath="abc\\def\\";
        System.out.println(getFilePathBasedOnClassPath(relativePath));
        relativePath="abc/def";
        System.out.println(getFilePathBasedOnClassPath(relativePath));
        relativePath="/abc/def";
        System.out.println(getFilePathBasedOnClassPath(relativePath));
        relativePath="/abc/def/";
        System.out.println(getFilePathBasedOnClassPath(relativePath));

        String fileString1="d:\\fold1\\abc.xlsx";
        String uuid=NslUtilUuid.generateUuidWithOutHyphen();

        System.out.println(getFileExtension(fileString1));
        System.out.println(fileString1.lastIndexOf("."));

        System.out.println(fileString1+ " => "+ buildFilePathWithIdTokenAtRear(fileString1, uuid));

        String[] suffixes={"x1","x2"};

        System.out.println(buildFilePathWithSuffixes(fileString1, suffixes));


    }
}
